package com.base.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.base.system.config.security.AuthUser;
import com.base.system.enums.HttpStatus;
import com.base.system.enums.UserState;
import com.base.system.exception.HttpException;
import com.base.system.jpa.entity.*;
import com.base.system.jpa.repository.*;
import com.base.system.mybatisPlus.entity.MybatisPermission;
import com.base.system.mybatisPlus.entity.MybatisRole;
import com.base.system.mybatisPlus.entity.MybatisUser;
import com.base.system.mybatisPlus.mapper.PermissionMapper;
import com.base.system.mybatisPlus.mapper.RoleMapper;
import com.base.system.mybatisPlus.mapper.UserMapper;
import com.base.system.service.UserService;
import com.base.system.util.PasswordUtil;
import com.base.system.web.vm.UserVm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private UserTokenRepository userTokenRepository;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private UserRoleRepository userRoleRepository;
    @Autowired
    private PermissionRepository permissionRepository;
    @Autowired
    private RoleRepository roleRepository;
    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private RoleMapper roleMapper;

    @Override
    public JpaUser findByIdFromJpa(Long id) {
        return userRepository.findById(id).get();
    }

    @Override
    public JpaUser save(JpaUser user) {
        validUser(user, true);
        JpaUser jpaUser = userRepository.saveAndFlush(user);
        userTokenRepository.save(new JpaUserToken().setUserId(jpaUser.getId()).setPassword(PasswordUtil.encode("123456")));
        return jpaUser;
    }

    private void validUser(JpaUser user, boolean isAdd) {
        Optional<JpaUser> userAcount = userRepository.findFirstByUserAcount(user.getUserAcount());
        if (userAcount.isPresent() && (!userAcount.get().getId().equals(user.getId()) || isAdd))
            throw new HttpException("用户名重复");
        Optional<JpaUser> email = userRepository.findFirstByEmail(user.getEmail());
        if (email.isPresent() && (!email.get().getId().equals(user.getId()) || isAdd))
            throw new HttpException("邮箱重复");
        Optional<JpaUser> idNumber = userRepository.findFirstByIdNumber(user.getIdNumber());
        if (idNumber.isPresent() && (!idNumber.get().getId().equals(user.getId()) || isAdd))
            throw new HttpException("身份证号码重复");
        Optional<JpaUser> phone = userRepository.findFirstByPhone(user.getPhone());
        if (phone.isPresent() && (!phone.get().getId().equals(user.getId()) || isAdd))
            throw new HttpException("电话号码重复");
    }

    @Override
    public MybatisUser findByIdFromMybatis(Long id) {
        return userMapper.selectById(id);
    }

    @Override
    public IPage<MybatisUser> page(Page<MybatisUser> page, UserVm vm) {
        QueryWrapper<MybatisUser> wrapper = new QueryWrapper<>();
        wrapper.like(StrUtil.isNotEmpty(vm.getNickName()), "nick_name", vm.getNickName())
                .like(StrUtil.isNotEmpty(vm.getUserName()), "user_acount", vm.getUserName())
                .like(StrUtil.isNotEmpty(vm.getRealName()), "real_name", vm.getRealName())
                .orderByDesc("create_time")
        ;
        return userMapper.selectPage(page, wrapper);
    }

    @Override
    public JpaUser udate(JpaUser user) {
        validUser(user, false);
        return userRepository.saveAndFlush(user);
    }

    @Override
    @Transactional
    public void saveUserRole(List<JpaUserRole> userRoles) {
        userRoleRepository.deleteAllByUserId(userRoles.get(0).getUserId());
        userRoleRepository.saveAll(userRoles);
    }

    @Override
    public List<Long> getUserWithRole(Long userId) {
        List<JpaUserRole> userRoles = userRoleRepository.findAllByUserId(userId);
        if (CollUtil.isEmpty(userRoles)) return null;
        return userRoles.stream().map(t -> t.getRoleId()).collect(Collectors.toList());
    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Optional<JpaUser> user = userRepository.findFirstByUserAcountOrPhoneOrEmailOrIdNumber(s, s, s, s);
        if (!user.isPresent()) throw new HttpException(HttpStatus.acount_error, "账户信息输入有误");
        Optional<JpaUserToken> token = userTokenRepository.findFirstByUserId(user.get().getId());
        if (!token.isPresent()) throw new HttpException(HttpStatus.acount_error, "账户信息输入有误");
        if (UserState.locked.equals(user.get().getState())) throw new HttpException(HttpStatus.acount_error, "账户已被锁定");
        else if (UserState.expired.equals(user.get().getState()))
            throw new HttpException(HttpStatus.acount_error, "账户已被注销");
        AuthUser securityUserInfo = new AuthUser();
        toUserInfo(user, token, securityUserInfo);
        return securityUserInfo;
    }

    @Transactional
    private void toUserInfo(Optional<JpaUser> user, Optional<JpaUserToken> token, AuthUser securityUserInfo) {
        Set<String> roles = new HashSet<>();

        Set<String> pres = new HashSet<>();
        BeanUtil.copyProperties(user.get(), securityUserInfo);
        securityUserInfo.setPassword(token.get().getPassword());
        if ("admin".equals(user.get().getUserAcount())) {
            //如果是超管
            List<MybatisPermission> list = permissionMapper.selectList(new LambdaQueryWrapper());
            if (CollUtil.isNotEmpty(list)) pres = list.stream().map(t -> t.getPerkey()).collect(Collectors.toSet());
            List<MybatisRole> list1 = roleMapper.selectList(new LambdaQueryWrapper());
            if (CollUtil.isNotEmpty(list1)) roles = list1.stream().map(t -> t.getRoleKey()).collect(Collectors.toSet());
        } else {
            List<JpaUserRole> userRoles = userRoleRepository.findAllByUserId(user.get().getId());
            if (CollUtil.isEmpty(userRoles)) return;
            Set<Long> collect = userRoles.stream().map(t -> t.getRoleId()).collect(Collectors.toSet());
            List<JpaRole> allRole = roleRepository.findAllById(collect);
            roles = allRole.stream().map(t -> t.getRoleKey()).collect(Collectors.toSet());
            List<List<JpaPermission>> collect1 = allRole.stream().map(t -> t.getPermissions()).collect(Collectors.toList());
            for (List<JpaPermission> jpaPermissions : collect1)
                for (JpaPermission jpaPermission : jpaPermissions) pres.add(jpaPermission.getPerkey());
        }
        securityUserInfo.setRoles(roles);
        securityUserInfo.setPres(pres);
    }
}
